package apple.eclipse.views;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.contexts.IContextActivation;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.part.ViewPart;

import apple.core.Apple;
import apple.core.KeyboardDecoder;
import apple.eclipse.model.Model;
import apple.ui.IMonitor;

public class NavigatorView extends ViewPart implements ISelectionListener {
   public static final String ID = "javapple2.navigator";

   private Model model;

   private TreeViewer viewer;

   public void createPartControl(Composite parent) {
      viewer = new TreeViewer(parent);
      viewer.setContentProvider(new AppleTreeContentProvider());
      viewer.setLabelProvider(new LabelProvider());
      model = Model.getInstance();
      viewer.setInput(model);
      getSite().setSelectionProvider(viewer);
      getSite().getPage().addSelectionListener(this);

      IContextService contextService = (IContextService) getSite().getService(
            IContextService.class);
      IContextActivation activation = contextService
            .activateContext("javapple2.context");
   }

   public void setFocus() {
      viewer.getControl().setFocus();
   }

   public void selectionChanged(IWorkbenchPart part, ISelection selection) {
      if (part == this) {
         return;
      }
      // the selection should be filtered
      viewer.setSelection(selection);
   }

   public void dispose() {
      getSite().getPage().removeSelectionListener(this);
   }

   private class AppleTreeContentProvider implements ITreeContentProvider,
         PropertyChangeListener {

      private TreeViewer viewer;

      public void propertyChange(PropertyChangeEvent event) {
         if (event.getPropertyName().equals(Model.PROPERTY_NAME)) {
            if (event.getNewValue() != null && event.getOldValue() == null) {
               viewer.refresh();
            } else if (event.getNewValue() == null
                  && event.getOldValue() != null) {
               viewer.refresh();
            } else {
               assert false;
            }
         }
      }

      public Object[] getElements(Object inputElement) {
         Model model = (Model) inputElement;
         Apple[] apples = model.getApples();
         return apples;
      }

      public boolean hasChildren(Object element) {
         return element instanceof Apple;
      }

      public Object[] getChildren(Object parentElement) {
         List<Object> children = new ArrayList<Object>();
         if (parentElement instanceof Apple) {
            Apple apple = (Apple) parentElement;
            IMonitor monitor = apple.getMonitor();
            KeyboardDecoder keyboardDecoder = apple.getKeyboardDecoder();
            if (monitor != null) {
               children.add(monitor);
            }
            if (keyboardDecoder != null) {
               children.add(keyboardDecoder);
            }
         }
         Object[] childArray = children.toArray();
         return childArray;
      }

      public Object getParent(Object element) {
         return null;
      }

      public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
         Model model;
         this.viewer = (TreeViewer) viewer;
         if (oldInput != null) {
            model = (Model) oldInput;
            model.removePropertyChangeListener(this);
         }
         if (newInput != null) {
            model = (Model) newInput;
            model.addPropertyChangeListener(this);
         }
      }

      public void dispose() {
      }
   }
}
